package com.authapi.sample.api.controller;

import com.authapi.sample.api.entity.*;
import com.authapi.sample.api.mapper.ClientMapper;
import com.authapi.sample.api.mapper.ClientRoleMapper;
import com.authapi.sample.api.mapper.MenuMapper;
import com.authapi.sample.api.model.Response.Authentication.UserValidationRequest;
import com.authapi.sample.api.model.Response.Authentication.VerificationCode;
import com.authapi.sample.api.model.Response.Authentication.VerificationCodeResponse;
import com.authapi.sample.api.model.Response.Common.Result;
import com.authapi.sample.api.model.Response.Common.ResultList;
import com.authapi.sample.api.service.impl.*;
import com.authapi.sample.api.utils.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/Authentication")
public class AuthenticationController {

    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private MenuServiceImpl menuService;

    @Autowired
    private LogServiceImpl logService;

    @Autowired
    private UserRoleServiceImpl userRoleService;

    @Autowired
    private RoleMenuServiceImpl roleMenuService;
    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleServiceImpl roleService;

    @Autowired
    TokenUtil tokenUtil;

    @Autowired
    private ClientMapper clientMapper;

    @PostMapping("/UserValidation")
    public Result<String> UserValidation(@RequestBody UserValidationRequest request) {
        //检查验证码
        var cacheManagerHelper = CacheManagerHelper.getInstance();
        var cacheCode = (String) cacheManagerHelper.get("VerificationCode_"+request.getCodeId());
        if(cacheCode==null ) {
            return Result.Fail("验证码错误");
        }
        if(!cacheCode.equals(request.getCode())) {
            return Result.Fail("验证码错误");
        }

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("name", request.getName())
                .eq("password", SHA256.sha256(request.getPassword()))
        ;
        User user = userService.getOne(queryWrapper);

        List<String> userRoles = userRoleService
                .query().eq("user_id",user.getId()).list()
                .stream().map(UserRole::getRoleId).collect(Collectors.toList());
        String roleIds = String.join(",", userRoles);

        boolean isAdmin = roleService.query().in("id",userRoles).eq("is_admin",1).exists();
        logService.save(new Log(UUID.randomUUID().toString(),user.getId(), LocalDateTime.now()));
        List<String> roleMenus = roleMenuService
                .query().in("role_id",userRoles).list()
                .stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        String menuIds =roleMenus.stream().distinct().collect(Collectors.joining(","));

        String token = tokenUtil.getToken(user.getId(),roleIds,menuIds, isAdmin?1:0);
        return Result.Success(token);

    }

    @GetMapping("/GetCurrentUser")
    public  Result<User> GetCurrentUser(HttpServletRequest httpServletRequest){
        //为空就返回错误
        String token = httpServletRequest.getHeader("token");
        if (null == token || token.trim().isEmpty()) {
            return Result.Fail("token为空");
        }

        Map<String, String> map = tokenUtil.parseToken(token);
        String userId = map.get("userId");
        User user = userService.getById(userId);
        return Result.Success(user);
    }

    @GetMapping("/GetUserClients")
    public  ResultList<List<Client>> GetCurrentUserClients(HttpServletRequest httpServletRequest){
        //为空就返回错误
        String token = httpServletRequest.getHeader("token");
        if (null == token || token.trim().isEmpty()) {
            return ResultList.Fail("token为空");
        }
        Map<String, String> map = tokenUtil.parseToken(token);
        String userId = map.get("userId");
        List<Client> Clients =  clientMapper.findClientsByUserId(userId);
        var distinctClients = Clients.stream().distinct().collect(Collectors.toList());
        return ResultList.Success(distinctClients);
    }

    @GetMapping("/GetVerificationCode")
    public  Result<VerificationCodeResponse>  GetVerificationCode(){
        Random random = new Random();
        int randomNumber = random.nextInt(10000);
        String code = String.format("%04d", randomNumber);
        String id = UUID.randomUUID().toString().replace("-", "");
        var img = VerifyCodeUtils.generateImage(code);
        var imgBaes64 = VerifyCodeUtils.BufferedImageToBase64(img);
        var cacheManagerHelper = CacheManagerHelper.getInstance();
        //var verificationCode = new VerificationCode(id,code);
        cacheManagerHelper.put("VerificationCode_"+id,code);
        return Result.Success(new VerificationCodeResponse(id,imgBaes64));
    }

    @GetMapping("/GetCode")
    public  Result<String>  GetCode(HttpServletRequest httpServletRequest){
        String code = UUID.randomUUID().toString().replace("-", "");
        //为空就返回错误
        String token = httpServletRequest.getHeader("token");
        if (null == token || token.trim().isEmpty()) {
            return Result.Fail("token为空");
        }
        Map<String, String> map = tokenUtil.parseToken(token);
        String userId = map.get("userId");
        var cacheManagerHelper = CacheManagerHelper.getInstance();
        cacheManagerHelper.put("Code_"+code,userId);
        return Result.Success(code);
    }

    @GetMapping("/GetTokenByCode")
    public  Result<String>  GetTokenByCode(String code){
        var cacheManagerHelper = CacheManagerHelper.getInstance();
        var userId = (String) cacheManagerHelper.get("Code_"+code);
        if(userId==null) {
            return Result.Fail("code无效");
        }
        User user = userService.getById(userId);
        List<String> userRoles = userRoleService
                .query().eq("user_id",user.getId()).list()
                .stream().map(UserRole::getRoleId).collect(Collectors.toList());
        String roleIds = String.join(",", userRoles);

        boolean isAdmin = roleService.query().in("id",userRoles).eq("is_admin",1).exists();
        logService.save(new Log(UUID.randomUUID().toString(),user.getId(), LocalDateTime.now()));
        List<String> roleMenus = roleMenuService
                .query().in("role_id",userRoles).list()
                .stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        String menuIds =roleMenus.stream().distinct().collect(Collectors.joining(","));
        String token = tokenUtil.getToken(user.getId(),roleIds,menuIds, isAdmin?1:0);
        return Result.Success(token);
    }

    @GetMapping("/GetUserMenus")
    public  ResultList<List<Menu>> GetCurrentUserMenus(HttpServletRequest httpServletRequest){
        //为空就返回错误
        String token = httpServletRequest.getHeader("token");
        if (null == token || token.trim().isEmpty()) {
            return ResultList.Fail("token为空");
        }
        Map<String, String> map = tokenUtil.parseToken(token);
        String userId = map.get("userId");
        List<Menu> Menus =  menuMapper.findMenusByUserId(userId);
        var distinctMenus = Menus.stream().distinct().collect(Collectors.toList());
        ListToTreeConverter<Menu> listToTreeConverter = new ListToTreeConverter<Menu>();
        for(Menu menu : Menus){
            var parentsIds = getAllParentsIds(new ArrayList<>(),menu.getId());
            for(String parentId : parentsIds){
                if(!distinctMenus.contains(menuService.getById(parentId))){
                    distinctMenus.add(menuService.getById(parentId));
                }
            }
        }
        return ResultList.Success(listToTreeConverter.recursionMethod(distinctMenus));
    }

    private  List<String> getAllParentsIds(List<String>ids, String id) {
        var _menu = menuService.getById(id);
        if(_menu.getParentId()==null || _menu.getParentId().isEmpty()){
            return ids;
        }
        else{
            ids.add(_menu.getParentId());
            return getAllParentsIds(ids,_menu.getParentId());
        }

    }
}
